/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = sqlserver_request.c                                           */
/*  NOTE      = TDS 请求解析                                                  */
/*  DATE      = 2014/09/30 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sqlserver_base_type.h"
#include "sqlserver_core.h"
#include "sqlserver_common.h"
#include "sqlserver_request.h"
#include "sqlserver_rpc.h"

#define MSSQL_TM_GET_DTC_ADDRESS    0
#define MSSQL_TM_PROPAGATE_XACT     1
#define MSSQL_TM_BEGIN_XACT         5    /* introduced in TDS 7.2 */
#define MSSQL_TM_PROMOTE_XACT       6    /* introduced in TDS 7.2 */
#define MSSQL_TM_COMMIT_XACT        7    /* introduced in TDS 7.2 */
#define MSSQL_TM_ROLLBACK_XACT      8    /* introduced in TDS 7.2 */
#define MSSQL_TM_SAVE_XACT          9    /* introduced in TDS 7.2 */

/*******************************************************************************
*  FUNC     :  判定是否需要生成request
*  ARGS     :  p_st_private (私有数据)
*           :  u8_request_type (request类型)
*  RTN      :  APM_L7_ANALYZE_SUCC
*              APM_L7_ANALYZE_FAIL
*  NOTE     :  p_st_private肯定不为NULL
*******************************************************************************/
FR_STATIC int __sqlserver_chk_request(L7session_sqlserver_private *p_st_private
                                   , uint8_t u8_request_type)
{
    L7session_sqlserver *p_st_sess = NULL;
    L7_req_sqlserver *p_st_req = NULL;
    /*
    * 上次解析的packet已经是一个完整的request了,
    * 但由于接收response或者解析的原因,没有解析到相应的response,
    * 这时需要将上一次的request信息释放掉
    */
    if (p_st_private->p_st_req
        && p_st_private->p_st_req->i_need_req_resp == MSSQL_RESPONSE)
    {
        /* 销毁上次的request信息 */
        sqlserver_destroy_request(&(p_st_private->p_st_req));
    }

    /* 需要创建request */
    if (p_st_private->p_st_req == NULL)
    {
        p_st_req = slqserver_create_request(u8_request_type);
        /* 创建失败 */
        if (p_st_req == NULL)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_private->p_st_req = p_st_req;
        p_st_sess = p_st_private->p_st_sess;
        p_st_req->i_cli_tds_ver_tmp = p_st_sess->i_cli_tds_ver;
        p_st_req->i_cli_tds_min_ver_tmp = p_st_sess->i_cli_tds_min_ver;
        p_st_req->i_cli_tds_max_ver_tmp = p_st_sess->i_cli_tds_max_ver;
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  取得并判断一个offset+length
*  ARGS     :  p_st_data(入力buffer)
*           :  pp_value(入力buffer长度)
*  RTN      :  FR_SUCC       (success)
*              FR_FAIL       (failed)
*  NOTE     :  p_st_data一定不为NULL
*******************************************************************************/
FR_STATIC int __sqlserver_get_once(Frbyte_Packet *p_st_data, char **pp_value)
{
    int i_ret = FR_SUCC;
    uint16_t u16_offset = 0;
    uint16_t u16_length = 0;
    uint32_t u32_acl_len = 0;
    unsigned int ui_output_size = 0;
    char *p_value = NULL;

    /* 取得offset */
    i_ret = bytebuff_get_short(p_st_data, MSSQL_TDS_USHORT_LEN
                               , &u16_offset, BYTE_LITTLE_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return FR_FAIL;
    }

    /* 取得长度 */
    i_ret = bytebuff_get_short(p_st_data, MSSQL_TDS_USHORT_LEN
                               , &u16_length, BYTE_LITTLE_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return FR_FAIL;
    }
    u32_acl_len = u16_length * 2;

    /* 所要取得数据长度是0 */
    if (u32_acl_len == 0)
    {
        return FR_SUCC;
    }

    /* 取得数据 */
    p_value = (char *)frmalloc(u32_acl_len);
    if (p_value == NULL)
    {
        return FR_FAIL;
    }
    i_ret = bytebuff_get_bytes_at(p_st_data, u16_offset, u32_acl_len, p_value);
    if (i_ret != FR_SUCC)
    {
        frfree(p_value);
        return FR_FAIL;
    }

    /* 需要取得数据 */
    if (pp_value != NULL)
    {
        /* 解码 */
        i_ret = iconv_to_utf8(p_value, u32_acl_len, APM_CHARSET_UCS2
                              , pp_value, &ui_output_size);
        frfree(p_value);
        /* 注：函数iconv_to_utf8只有当返回值是2时是严重错误 */
        if (i_ret == 2)
        {
            return FR_FAIL;
        }
    }
    else
    {
        frfree(p_value);
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析offset
*  ARGS     :  p_inbuffer(入力buffer)
*           :  ui_buffer_len(入力buffer长度)
*           :  ui_offset(入力buffer的offset)
*           :  i_cli_tds_ver(协议版本号)
*           :  i_extension_flag(extension版本号)
*           :  pp_cli_host_user(客户端主机名)
*           :  pp_program(客户端程序名)
*           :  pp_db_name(数据库名)
*           :  p_db_user(数据库用户名)
*  RTN      :  FR_SUCC       (success)
*              FR_FAIL       (failed)
*  NOTE     :  p_st_data一定不为NULL
*******************************************************************************/
FR_STATIC int __sqlserver_parse_offset_data(Frbyte_Packet *p_st_data
                                         , int i_cli_tds_ver
                                         , int i_extension_flag
                                         , char **pp_cli_host_user
                                         , char **pp_program
                                         , char **pp_db_name
                                         , char **pp_db_user)
{
    int i_ret = FR_SUCC;

    /* client machine name */
    i_ret = __sqlserver_get_once(p_st_data, pp_cli_host_user);
    if (i_ret != FR_SUCC)
    {
        return FR_FAIL;
    }

    /* client user id */
    i_ret = __sqlserver_get_once(p_st_data, pp_db_user);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* password supplied by client */
    i_ret = __sqlserver_get_once(p_st_data, NULL);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* client application name */
    i_ret = __sqlserver_get_once(p_st_data, pp_program);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* server name */
    i_ret = __sqlserver_get_once(p_st_data, NULL);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* extension block(Introduced in TDS 7.4) */
    if (i_cli_tds_ver >= MSSQL_TDS_VER_74 && i_extension_flag == 1)
    {
        i_ret = bytebuff_skip(p_st_data, MSSQL_TDS_USHORT_LEN + MSSQL_TDS_USHORT_LEN);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }
    }
    else
    {
        /* unused parameters */
        i_ret = __sqlserver_get_once(p_st_data, NULL);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }
    }

    /* interface library name */
    i_ret = __sqlserver_get_once(p_st_data, NULL);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* initial language */
    i_ret = __sqlserver_get_once(p_st_data, NULL);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* initial database */
    i_ret = __sqlserver_get_once(p_st_data, pp_db_name);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* unique client ID */
    i_ret = bytebuff_skip(p_st_data, 6);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* SSPI data */
    i_ret = __sqlserver_get_once(p_st_data, NULL);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    /* DBfile */
    i_ret = __sqlserver_get_once(p_st_data, NULL);
    if (i_ret != FR_SUCC)
    {
        goto error;
    }

    if (i_cli_tds_ver >= MSSQL_TDS_VER_72)
    {
        /* new password for the specified login(Introduced in TDS 7.2) */
        i_ret = __sqlserver_get_once(p_st_data, NULL);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }

        /* SSPI(Introduced in TDS 7.2) */
        i_ret = bytebuff_skip(p_st_data, MSSQL_TDS_DWORD_LEN);
        if (i_ret != FR_SUCC)
        {
            goto error;
        }
    }

    return FR_SUCC;

error:
    sqlserver_free((void **)pp_db_name);
    sqlserver_free((void **)pp_program);
    sqlserver_free((void **)pp_db_user);
    sqlserver_free((void **)pp_cli_host_user);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析ALL_HEADERS
*  ARGS     :  p_st_data(入力数据)
*           :  p_i_tds_ver(确定的TDS版本号)
*           :  p_i_tds_min_ver(可能的的TDS最小版本号)
*           :  p_i_tds_max_ver(可能的的TDS最大版本号)
*           :  i_whole_flg(数据是否完整标识)
*  RTN      :  APM_L7_ANALYZE_TODO
*              APM_L7_ANALYZE_SUCC
*              APM_L7_ANALYZE_FAIL
*  NOTE     :  p_st_data一定不为NULL
*******************************************************************************/
FR_STATIC int __sqlserver_all_headers_skip(Frbyte_Packet *p_st_data
                                        , int *p_i_tds_ver
                                        , int *p_i_tds_min_ver
                                        , int *p_i_tds_max_ver
                                        , int i_whole_flg)
{
    int i_ret = FR_SUCC;
    int i_tds_ver = *p_i_tds_ver;
    int i_tds_min_ver = *p_i_tds_min_ver;
    int i_tds_max_ver = *p_i_tds_max_ver;
    uint32_t u32_total_len = 0;
    uint32_t u32_header_len = 0;
    uint16_t u16_header_type = 0;
    unsigned int ui_real_len = 0;
    unsigned int ui_remaining = bytebuff_remaining(p_st_data);

    /*
    *  由于ALL_HEADERS是可选的
    *  所以假如不合符ALL_HEADERS格式直接返回,
    *  当做没有ALL_HEADERS项.
    */

    /*
    *  The ALL_HEADERS rule, the Query Notifications header, and the
    *  Transaction Descriptor header were introduced in TDS 7.2 .
    *  The Trace Activity header was introduced in TDS 7.4 .
    */
    if ((i_tds_ver != MSSQL_TDS_VER_NULL && i_tds_ver < MSSQL_TDS_VER_72)
       || (i_tds_ver == MSSQL_TDS_VER_NULL && i_tds_max_ver < MSSQL_TDS_VER_72))
    {
        return APM_L7_ANALYZE_SUCC;
    }

    /* 数据长度本身就比MSSQL_TDS_DWORD_LEN小 */
    if (ui_remaining < MSSQL_TDS_DWORD_LEN)
    {
        goto unknown;
    }

    /* 取得total_length的值 */
    i_ret = bytebuff_get_int(p_st_data, MSSQL_TDS_DWORD_LEN
                            , &u32_total_len, BYTE_LITTLE_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    u32_total_len -= MSSQL_TDS_DWORD_LEN;
    ui_real_len = u32_total_len;

    /* 判断遗留数据长度是否足够 */
    ui_remaining = bytebuff_remaining(p_st_data);
    if (ui_remaining < u32_total_len)
    {
        ui_real_len = ui_remaining;
    }

    /* 解析并且check每个header */
    while (ui_real_len)
    {
        /* 数据长度本身就比MSSQL_TDS_DWORD_LEN小 */
        if (ui_real_len < MSSQL_TDS_DWORD_LEN)
        {
            goto unknown;
        }

        /* 取得header_length的值 */
        i_ret = bytebuff_get_int(p_st_data, MSSQL_TDS_DWORD_LEN
                                , &u32_header_len, BYTE_LITTLE_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }

        /*
        *  如果header_length的值比total_length长或者
        *  header_length小于header_length本身长度+header_type的长度,
        *  则判定不符合格式
        */
        if (u32_header_len < MSSQL_TDS_DWORD_LEN + MSSQL_TDS_USHORT_LEN
            || u32_header_len > 256)
        {
            goto noheaders;
        }

        if (u32_header_len > ui_real_len)
        {
            goto unknown;
        }
        /* 更新total length */
        ui_real_len -= u32_header_len;

        /* 取得header type */
        i_ret = bytebuff_get_short(p_st_data, MSSQL_TDS_USHORT_LEN
                                  , &u16_header_type, BYTE_LITTLE_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }

        /* header type值判定(现今只有三个值1,2,3) */
        if (u16_header_type == 1 || u16_header_type == 2)
        {
            if (i_tds_min_ver < MSSQL_TDS_VER_72)
            {
                i_tds_min_ver = MSSQL_TDS_VER_72;
            }
        }
        else if (u16_header_type == 3)
        {
            if (i_tds_ver != MSSQL_TDS_VER_NULL && i_tds_ver < MSSQL_TDS_VER_74)
            {
                goto noheaders;
            }

            if (i_tds_min_ver < MSSQL_TDS_VER_74)
            {
                i_tds_min_ver = MSSQL_TDS_VER_74;
            }
        }
        else
        {
            goto noheaders;
        }

        /* 取得header value的长度 */
        u32_header_len -= MSSQL_TDS_DWORD_LEN + MSSQL_TDS_USHORT_LEN;
        /* 跳过header value */
        i_ret = bytebuff_skip(p_st_data, u32_header_len);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }
    }

    /* 实际上还有属于all_headers的数据 */
    if (ui_remaining < u32_total_len)
    {
        goto unknown;
    }

    /* 设置TDS版本号 */
    if (i_tds_ver == MSSQL_TDS_VER_NULL)
    {
        if (i_tds_min_ver > i_tds_max_ver)
        {
            *p_i_tds_min_ver = i_tds_min_ver;
            *p_i_tds_max_ver = MSSQL_TDS_VER_74;
            if (*p_i_tds_min_ver == *p_i_tds_max_ver)
            {
                *p_i_tds_ver = i_tds_min_ver;
            }
        }
        else if (i_tds_min_ver == i_tds_max_ver)
        {
            *p_i_tds_ver = i_tds_min_ver;
            *p_i_tds_min_ver = i_tds_min_ver;
            *p_i_tds_max_ver = i_tds_min_ver;
        }
        else
        {
            *p_i_tds_min_ver = i_tds_min_ver;
        }
    }
    return APM_L7_ANALYZE_SUCC;

unknown:
    /* 根据TDS协议,ALL_HEADERS都在packet的开头 */
    bytebuff_rewind(p_st_data);
    if (i_whole_flg == FR_YES)
    {
        return APM_L7_ANALYZE_SUCC;
    }
    else
    {
        return APM_L7_ANALYZE_TODO;
    }

noheaders:
    bytebuff_rewind(p_st_data);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析LOGIN7数据
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (need more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int sqlserver_parse_login7(Conntrack *p_st_conn
                           , L7session_sqlserver_private *p_st_private
                           , Frhash_header *p_st_hash_report
                           , int i_cancel_flg
                           , int i_whole_flg)
{
    /*
    * LOGIN7定义如下：
    *   LOGIN7 = Length
    *            TDSVersion
    *            PacketSize
    *            ClientProgVer
    *            ClientPID
    *            ConnectionID
    *            OptionFlags1
    *            OptionFlags2
    *            TypeFlags
    *           (FRESERVEDBYTE / OptionFlags3)
    *            ClientTimZone
    *            ClientLCID
    *            OffsetLength
    *            Data
    *            [FeatureExt]
    */
    int i_ret = FR_SUCC;
    uint8_t u8_flags1 = 0;
    uint8_t u8_flags3 = 0;
    size_t s_skip_len = 0;
    int i_cli_tds_ver = 0;
    int i_extension_flag = 0;
    uint32_t u32_login7_size = 0;
    //uint32_t u32_remaing_len = 0;
    char *p_cli_host_user = NULL;                /* 客户端的主机名 */
    char *p_program = NULL;                      /* 客户端的程序名 */
    char *p_db_name = NULL;                      /* 数据库名 */
    char *p_db_user = NULL;                      /* 登陆数据库用户名 */
    L7_session *p_st_session = NULL;
    L7session_sqlserver *p_st_sqlserver_session = p_st_private->p_st_sess;
    L7_fragment_sqlserver *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_LOGIN7);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("__sqlserver_chk_request failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* LOGIN的没有大的数据,接收完了之后再解析 */
    if (i_whole_flg != FR_YES)
    {
        frdbg("Packet Login7: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    p_st_private->p_st_req->i_cancel_flg = i_cancel_flg;

    /* 取得LOGIN7结构长度 */
    i_ret = bytebuff_get_int(p_st_data, MSSQL_TDS_DWORD_LEN
                            , &u32_login7_size, BYTE_LITTLE_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        frdbg("Get LOGIN7 packet length failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 有些版本的长度格式不正，不进行严格的格式check */
    /* 判断长度是否正确 */
    //u32_remaing_len = bytebuff_remaining(p_st_data);
    //if (u32_remaing_len + MSSQL_TDS_DWORD_LEN != u32_login7_size)
    //{
    //    frdbg("Login7 packet length is incorrect!\n");
    //    return APM_L7_ANALYZE_FAIL;
    //}

    /* LOGIN7版本号取得 */
    i_ret = sqlserver_tds_ver_get(p_st_data, MSSQL_CLI2SRV, &i_cli_tds_ver);
    /* LOGIN7结构格式不正 */
    if (i_ret == FR_FAIL)
    {
        frdbg("Get client tds version failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 跳过PacketSize,ClientProgVer,ClientPID,ConnectionID这些不必关心的字段 */
    s_skip_len = 4 + 4 + 4 + 4;
    i_ret = bytebuff_skip(p_st_data, s_skip_len);
    if (i_ret == FR_FAIL)
    {
        frdbg("Login7 packet format is incorrect!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 取得OptionFlags1 */
    i_ret = bytebuff_get_char(p_st_data, &u8_flags1);
    if (i_ret == FR_FAIL)
    {
        frdbg("Login7 packet format is incorrect!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得字节序 */
    if (u8_flags1 & 0x01)
    {
        p_st_sqlserver_session->i_endian = BYTE_BIG_ENDIAN;
    }
    else
    {
        p_st_sqlserver_session->i_endian = BYTE_LITTLE_ENDIAN;
    }
    /* 取得charset */
    if (u8_flags1 & 0x02)
    {
        snprintf(p_st_sqlserver_session->arr_client_charset, 20, "%s", "CP500");
    }
    else
    {
        snprintf(p_st_sqlserver_session->arr_client_charset, 20, "%s", "ASCII");
    }
    /* 取得float type */
    if (u8_flags1 & 0x04)
    {
        p_st_sqlserver_session->i_float_type = FRTDS_FLT_IEEE_LO;
    }
    else if (u8_flags1 & 0x08)
    {
        p_st_sqlserver_session->i_float_type = FRTDS_FLT_VAXD;
    }
    else
    {
        if (p_st_sqlserver_session->i_endian == BYTE_BIG_ENDIAN)
        {
            p_st_sqlserver_session->i_float_type = FRTDS_FLT_IEEE_LO;
        }
        else
        {
            p_st_sqlserver_session->i_float_type = FRTDS_FLT_IEEE_HI;
        }
    }

    /* 跳过OptionFlags2,TypeFlags这些不必关心的字段 */
    s_skip_len = 1 + 1;
    i_ret = bytebuff_skip(p_st_data, s_skip_len);
    if (i_ret == FR_FAIL)
    {
        frdbg("Login7 packet format is incorrect!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 取得OptionFlags3 */
    i_ret = bytebuff_get_char(p_st_data, &u8_flags3);
    if (i_ret == FR_FAIL)
    {
        frdbg("Login7 packet format is incorrect!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    i_extension_flag = u8_flags3 & 8;

    /* 跳过ClientTimZone,ClientLCID这些不必关心的字段 */
    s_skip_len = 4 + 4;
    i_ret = bytebuff_skip(p_st_data, s_skip_len);
    if (i_ret == FR_FAIL)
    {
        frdbg("Login7 packet format is incorrect!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* parser offset and length */
    i_ret = __sqlserver_parse_offset_data(p_st_data, i_cli_tds_ver
                                         , i_extension_flag, &p_cli_host_user
                                         , &p_program, &p_db_name, &p_db_user);
    if (i_ret == FR_FAIL)
    {
        frdbg("Parse offset failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 设置sqlserver的私有session */
    p_st_sqlserver_session->p_cli_host_user = p_cli_host_user;
    p_st_sqlserver_session->p_program = p_program;
    p_st_sqlserver_session->p_db_name = p_db_name;
    p_st_sqlserver_session->p_db_user = p_db_user;
    p_st_sqlserver_session->i_cli_tds_ver = i_cli_tds_ver;
    p_st_session = frct_get_session(p_st_conn);
    frct_set_session_username(p_st_session, p_db_user);
    /* 下次要接受的packet是response */
    p_st_private->p_st_req->i_need_req_resp = MSSQL_RESPONSE;

    /* login成功时候上报 */
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析SQL Batch
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(sqlserver的私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (need more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int sqlserver_parse_sqlbatch(Conntrack *p_st_conn
                            , L7session_sqlserver_private *p_st_private
                            , Frhash_header *p_st_hash_report
                            , int i_cancel_flg
                            , int i_whole_flg)
{
    /*
    * SQL Batch定义如下：
    *   SQLBatch =  ALL_HEADERS
    *               SQLText
    *  SQLText = UNICODESTREAM
    */
    int i_ret = FR_SUCC;
    long l_cursor_id = 0;
    unsigned int ui_reaming_len = 0;
    unsigned int ui_output_size = 0;
    unsigned long ul_req_sequence = 0;
    char *p_buffer = NULL;
    char *p_sql_text = NULL;
    Mssql_cursor *p_st_cursor = NULL;
    L7_req_sqlserver *p_st_req = NULL;
    Sql_resultset *p_st_resultset = NULL;
    Sql_statement *p_st_statement = NULL;
    Frreport_body_data *p_st_report_body = NULL;
    L7session_sqlserver *p_st_session = p_st_private->p_st_sess;
    L7_fragment_sqlserver *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_SQLBATCH);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("__sqlserver_chk_request failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /* 由于SQL Batch里解析不出数据类型,所以等所有packet都收完后一起解析 */
    if (i_whole_flg != FR_YES)
    {
        frdbg("Packet SQLBatch: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }

    p_st_req = p_st_private->p_st_req;
    /* 设置cancel标示 */
    p_st_req->i_cancel_flg = i_cancel_flg;
    /* 下次要接受的packet是response */
    p_st_req->i_need_req_resp = MSSQL_RESPONSE;

    /* 跳过ALL_HEADERS */
    i_ret = __sqlserver_all_headers_skip(p_st_data, &p_st_req->i_cli_tds_ver_tmp
                                        , &p_st_req->i_cli_tds_min_ver_tmp
                                        , &p_st_req->i_cli_tds_max_ver_tmp
                                        , i_whole_flg);
    if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        frdbg("Skip all_headers failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得剩余长度 */
    ui_reaming_len = bytebuff_remaining(p_st_data);
    p_buffer = (char *)frmalloc(ui_reaming_len);
    if (p_buffer == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得剩余数据 */
    i_ret = bytebuff_get_bytes(p_st_data, p_buffer, ui_reaming_len);
    if (i_ret != FR_SUCC)
    {
        frdbg("Sqlbatch packet format is incorrect!\n");
        frfree(p_buffer);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 取得SQLText */
    i_ret = iconv_to_utf8(p_buffer, ui_reaming_len, APM_CHARSET_UCS2
                         , &p_sql_text, &ui_output_size);
    frfree(p_buffer);
    /* 2表示文字code变换时出现了严重错误 */
    if (i_ret == 2)
    {
        frdbg("iconv failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }

    /*
    * 在用microsoft的驱动时, 解析出例如[sp_cursorclose 180150004]
    * 是有特殊含义的, 需要将他当做关闭游标的操作处理
    */
    if (ui_output_size >= 16
        && strncasecmp(p_sql_text, "sp_cursorclose ", 15) == 0
        && strspn(p_sql_text + 15, "0123456789") == (ui_output_size - 15))
    {
        /* 取得cursor ID */
        l_cursor_id = atol(p_sql_text + 15);
        p_st_cursor = sqlserver_get_cursor_info(&(p_st_private->list_cursor)
                                                , l_cursor_id);
        if (p_st_cursor)
        {
            frfree(p_sql_text);
            p_st_req->u8_packet_type = MSSQL_TDS_RPCREQUEST;
            p_st_req->u8_request_type = MSSQL_TDS_RPCREQUEST;
            p_st_req->u16_rpc_type = MSSQL_PREPARE_CURSOR_CLOSE;
            p_st_req->l_uid = l_cursor_id;
            /* 取得statement和resultset的索引 */
            p_st_statement = p_st_cursor->p_st_statement;
            p_st_resultset = p_st_cursor->p_st_resultset;

            /* 更新请求结果集信息 */
            frdb_set_resultset_req2(p_st_resultset
                                   , p_st_fragment->ui_total_len
                                   , &(p_st_fragment->st_first_timestamp)
                                   , &(p_st_fragment->st_end_timestamp));
            /* 设置statement和resultset的索引 */
            p_st_req->p_st_statement = p_st_statement;
            p_st_req->p_st_resultset = p_st_resultset;

            /* 创建report body */
            p_st_report_body = sqlserver_new_report_body(p_st_conn, p_st_session);
            /* 创建report body失败时，不释放做成的request */
            if (p_st_report_body == NULL)
            {
                frdbg("sqlserver_new_report_body failed!\n");
                return APM_L7_ANALYZE_SUCC;
            }

            /* 上报request数据 */
            i_ret = frdb_report_req2(p_st_conn, p_st_hash_report, p_st_statement
                                     , p_st_resultset, &p_st_report_body);
            /* 上报request数据失败时，不释放做成的request */
            if (i_ret != FR_SUCC)
            {
                frdbg("frdb_report_req2 failed!\n");
                frreport_body_free(&p_st_report_body);
                return APM_L7_ANALYZE_SUCC;
            }

            //frdbg("Parse sp_cursorclose %ld success!\n", l_cursor_id);
            return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
        }
        frdbg("NO matching cursor info, treat it as general sql statement!\n");
    }

    /* 创建statement */
    p_st_statement = frdb_create_statement();
    if (p_st_statement == NULL)
    {
        frdbg("Create sqlbatch statement failed!\n");
        sqlserver_free((void **)&p_sql_text);
        return APM_L7_ANALYZE_FAIL;
    }
    /* 设置sql statement */
    frdb_set_sql(p_st_statement, p_sql_text);

    /* 创建结果集 */
    ul_req_sequence = frct_seq_increase(p_st_conn);
    p_st_resultset = frdb_create_resultset(ul_req_sequence);
    if (p_st_resultset == NULL)
    {
        frdbg("Create sqlbatch resultset failed!\n");
        frdb_statement_free(&p_st_statement);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 追加结果集到statement */
    i_ret = frdb_add_resultset(p_st_statement, p_st_resultset);
    if (i_ret != FR_SUCC)
    {
        frdbg("Insert resultset into statement failed!\n");
        frdb_statement_free(&p_st_statement);
        frdb_resultset_free(&p_st_resultset);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 设置结果集信息 */
    frdb_set_resultset_req2(p_st_resultset
                           , p_st_fragment->ui_total_len
                           , &(p_st_fragment->st_first_timestamp)
                           , &(p_st_fragment->st_end_timestamp));

    /* 设置request索引 */
    p_st_req->p_st_statement = p_st_statement;
    p_st_req->p_st_resultset = p_st_resultset;

    /* 设置版本信息 */
    p_st_session->i_cli_tds_ver = p_st_req->i_cli_tds_ver_tmp;
    p_st_session->i_cli_tds_min_ver = p_st_req->i_cli_tds_min_ver_tmp;
    p_st_session->i_cli_tds_max_ver = p_st_req->i_cli_tds_max_ver_tmp;

    /* 创建report body */
    p_st_report_body = sqlserver_new_report_body(p_st_conn, p_st_session);
    /* 创建report body失败时，不释放做成的request */
    if (p_st_report_body == NULL)
    {
        frdbg("sqlserver_new_report_body failed!\n");
        return APM_L7_ANALYZE_SUCC;
    }
    /* 上报request数据 */
    i_ret = frdb_report_req2(p_st_conn, p_st_hash_report, p_st_statement
                             , p_st_resultset, &p_st_report_body);
    /* 上报request数据失败时，不释放做成的request */
    if (i_ret != FR_SUCC)
    {
        frdbg("frdb_report_req2 failed!\n");
        frreport_body_free(&p_st_report_body);
        return APM_L7_ANALYZE_SUCC;
    }

    //frdbg("Parse SQLBATCH success!\n");
    return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
}

/*******************************************************************************
*  FUNC     :  解析PRETDS7LOGIN
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (todo)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int sqlserver_parse_pretds7login(Conntrack *p_st_conn
                                , L7session_sqlserver_private *p_st_private
                                , Frhash_header *p_st_hash_report
                                , int i_cancel_flg
                                , int i_whole_flg)
{
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_PRETDS7LOGIN);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* LOGIN的没有大的数据,接收完了之后再解析 */
    if (i_whole_flg != FR_YES)
    {
        frdbg("Packet PRETDS7LOGIN: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }

    //todo TDS7.0以下版本的暂不解析
    p_st_private->p_st_req->i_need_req_resp = MSSQL_RESPONSE;
    p_st_private->p_st_req->i_cancel_flg = i_cancel_flg;
    return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
}

/*******************************************************************************
*  FUNC     :  解析RPC请求
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (todo)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int sqlserver_parse_rpc(Conntrack *p_st_conn
                       , L7session_sqlserver_private *p_st_private
                       , Frhash_header *p_st_hash_report
                       , int i_cancel_flg
                       , int i_whole_flg)
{
    /*
    * RPCRequest定义如下：
        RPCRequest =  ALL_HEADERS
                      RPCReqBatch
                      *((BatchFlag / NoExecFlag) RPCReqBatch)
                      [BatchFlag / NoExecFlag]
    * RPCReqBatch = NameLenProcID
                    OptionFlags
                    *ParameterData
    * ParameterData = ParamMetaData
                      ParamLenData;
    *ParamMetaData = B_VARCHAR
                     StatusFlags
                    (TYPE_INFO / TVP_TYPE_INFO)
    * ParamLenData = TYPE_VARBYTE
    */
    int i_ret = APM_L7_ANALYZE_SUCC;
    uint16_t u16_length = 0;
    uint32_t u32_length = 0;
    uint16_t u16_process_id = 0;
    unsigned int ui_remaining = 0;
    unsigned int ui_process_len = 0;
    char *p_btyes = NULL;
    char *p_process_name = NULL;
    L7_req_sqlserver *p_st_req = NULL;
    Sql_statement *p_st_statement = NULL;
    L7_fragment_sqlserver *p_st_fragment = p_st_private->p_st_fragment;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_RPCREQUEST);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        frdbg("__sqlserver_chk_request failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    p_st_req = p_st_private->p_st_req;

    /* 将位置设置到上次解析正确的位置 */
    bytebuff_setPosition(p_st_data, p_st_fragment->ui_parsed_index);
    /* 如果之前还未解析过,则从头开始解析共通头 */
    if (p_st_fragment->ui_parsed_index == 0)
    {
        /* 解析ALL_HEADERS */
        i_ret = __sqlserver_all_headers_skip(p_st_data
                                            , &p_st_req->i_cli_tds_ver_tmp
                                            , &p_st_req->i_cli_tds_min_ver_tmp
                                            , &p_st_req->i_cli_tds_max_ver_tmp
                                            , i_whole_flg);
        if (i_ret != APM_L7_ANALYZE_SUCC)
        {
            frdbg("Skip all_headers failed!\n");
            return i_ret;
        }
        /* 取得剩余长度 */
        ui_remaining = bytebuff_remaining(p_st_data);
        if (ui_remaining <= MSSQL_TDS_USHORT_LEN)
        {
            goto error;
        }
        ui_remaining -= MSSQL_TDS_USHORT_LEN;
        /* 取得process名或者process ID */
        i_ret = bytebuff_get_short(p_st_data, MSSQL_TDS_USHORT_LEN
                                  , &u16_length, BYTE_LITTLE_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }

        /* 根据TDS协议规定如果是以0XFFFF开头的话后面跟着的是两位的process ID */
        if (u16_length == 0xffff)
        {
            /* ProcIDSwitch + OptionFlags */
            if (ui_remaining < MSSQL_TDS_USHORT_LEN + 2)
            {
                goto error;
            }
            /* 取得process ID */
            i_ret = bytebuff_get_short(p_st_data, MSSQL_TDS_USHORT_LEN
                                       , &u16_process_id, BYTE_LITTLE_ENDIAN);
            if (i_ret != FR_SUCC)
            {
                return APM_L7_ANALYZE_FAIL;
            }
            /* 设置RPC类型 */
            p_st_req->u16_rpc_type = u16_process_id;
        }
        /* process name */
        else
        {
            u32_length = u16_length * 2;
            /* processName + OptionFlags */
            if (ui_remaining < u32_length + 2)
            {
                goto error;
            }
            /* 取得process name值 */
            if (u32_length)
            {
                p_btyes = (char *)frmalloc(u32_length);
                if (p_btyes == NULL)
                {
                    return APM_L7_ANALYZE_FAIL;
                }
                /* 取得指定bytes */
                i_ret = bytebuff_get_bytes(p_st_data, p_btyes, u32_length);
                if (i_ret != FR_SUCC)
                {
                    frfree(p_btyes);
                    return APM_L7_ANALYZE_FAIL;
                }
                /* 取得process name */
                i_ret = iconv_to_utf8(p_btyes, u32_length, APM_CHARSET_UCS2
                                     , &p_process_name, &ui_process_len);
                frfree(p_btyes);
                /* 注：函数iconv_to_utf8只有当返回值是2时是严重错误 */
                if (i_ret == 2)
                {
                    return APM_L7_ANALYZE_FAIL;
                }
            }

            if (p_process_name && strncasecmp(p_process_name, "sp_cursorfetch", 14) == 0)
            {
                sqlserver_free((void **)&p_process_name);
                p_st_req->u16_rpc_type = MSSQL_PREPARE_CURSOR_FETCH;
            }
            else if (p_process_name && strncasecmp(p_process_name, "sp_cursorclose", 14) == 0)
            {
                sqlserver_free((void **)&p_process_name);
                p_st_req->u16_rpc_type = MSSQL_PREPARE_CURSOR_CLOSE;
            }
            else
            {
                //frdbg("RPCNAME=[%s]\n", p_process_name);
                /* 创建statement */
                p_st_statement = frdb_create_statement();
                if (p_st_statement == NULL)
                {
                    sqlserver_free((void **)&p_process_name);
                    return APM_L7_ANALYZE_FAIL;
                }
                /* 设置sql */
                frdb_set_sql(p_st_statement, p_process_name);
                p_st_req->p_st_statement = p_st_statement;
                /* 设置RPC类型 */
                p_st_req->u16_rpc_type = MSSQL_PREPARE_RPC_NAME;
            }
        }

        /* 跳过OptionFlags */
        bytebuff_skip(p_st_data, 2);
        /* 设置解析到的位置 */
        p_st_fragment->ui_parsed_index = bytebuff_getPosition(p_st_data);
    }

    /* 很据process ID解析普通的prepare */
    switch (p_st_req->u16_rpc_type)
    {
        case MSSQL_PREPARE_CURSOR:
            i_ret = sqlserver_rpc_cursor(p_st_conn, p_st_private
                                        , p_st_hash_report
                                        , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_OPEN:
            i_ret = sqlserver_rpc_cursor_open(p_st_conn, p_st_private
                                             , p_st_hash_report
                                             , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_PREPARE:
            i_ret = sqlserver_rpc_prep(p_st_conn, p_st_private, p_st_hash_report
                                      , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_EXECUTE:
            i_ret = sqlserver_rpc_cursor_exec(p_st_conn, p_st_private
                                             , p_st_hash_report
                                             , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_PREPEXEC:
            i_ret = sqlserver_rpc_cursor_prep_exec(p_st_conn, p_st_private
                                                   , p_st_hash_report
                                                   , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_UNPREPARE:
            i_ret = sqlserver_rpc_cursor_unprep(p_st_conn, p_st_private
                                               , p_st_hash_report
                                               , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_FETCH:
            i_ret = sqlserver_rpc_cursor_fetch(p_st_conn, p_st_private
                                              , p_st_hash_report
                                              , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_OPTION:
            i_ret = sqlserver_rpc_cursor_opt(p_st_conn, p_st_private
                                            , p_st_hash_report
                                            , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_CURSOR_CLOSE:
            i_ret = sqlserver_rpc_cursor_close(p_st_conn, p_st_private
                                              , p_st_hash_report
                                              , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_EXECUTE_SQL:
            i_ret = sqlserver_rpc_exec_sql(p_st_conn, p_st_private
                                           , p_st_hash_report
                                           , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_PREPARE:
            i_ret = sqlserver_rpc_prep(p_st_conn, p_st_private, p_st_hash_report
                                      , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_EXECUTE:
            i_ret = sqlserver_rpc_exec(p_st_conn, p_st_private
                                      , p_st_hash_report
                                      , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_PREPEXEC:
            i_ret = sqlserver_rpc_prepexec(p_st_conn, p_st_private
                                           , p_st_hash_report
                                           , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_PREPEXECRPC:
            i_ret = sqlserver_rpc_prep_rpc(p_st_conn, p_st_private
                                           , p_st_hash_report
                                           , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_UNPREPARE:
            i_ret = sqlserver_rpc_unprep(p_st_conn, p_st_private
                                        , p_st_hash_report
                                        , i_cancel_flg, i_whole_flg);
            break;

        case MSSQL_PREPARE_RPC_NAME:
            i_ret = sqlserver_rpc_name(p_st_conn, p_st_private
                                      , p_st_hash_report
                                      , i_cancel_flg, i_whole_flg);
            break;

        default:
            return APM_L7_ANALYZE_FAIL;
    }

    return i_ret;

error:
    if (i_whole_flg == FR_YES)
    {
        frdbg("Parse RPC failed!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    else
    {
        frdbg("Packet RPC: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
}

/*******************************************************************************
*  FUNC     :  解析TransMgrReq请求
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (todo)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     : 事务处理，现状是没有抓取到数据，且它是没有SQl语句的，
*             只能通过响应的RequestType来确定事务类型
*             todo 能解析出来，但是出力格式待定，先当做不上报
*******************************************************************************/
int sqlserver_parse_transaction(Conntrack *p_st_conn
                               , L7session_sqlserver_private *p_st_private
                               , Frhash_header *p_st_hash_report
                               , int i_cancel_flg
                               , int i_whole_flg)
{
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_TRANSMGRREQ);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* LOGIN的没有大的数据,接收完了之后再解析 */
    if (i_whole_flg != FR_YES)
    {
        frdbg("Packet TransMgrReq: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }

    //todo 出力格式未定，暂时不做解析
    p_st_private->p_st_req->i_need_req_resp = MSSQL_RESPONSE;
    p_st_private->p_st_req->i_cancel_flg = i_cancel_flg;
    return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);

    /*
    * TransMgrReq = ALL_Headers
                    RequestType
                   [RequestPayload]
    *  RequestType = USHORT
    */
    //int i_ret = FR_SUCC;
    //int i_cli_tds_min_ver = 0;
    //int i_begin_xact_flag = 0;
    //unsigned char uc_isolation_level = 0;
    //unsigned int ui_request_type = 0;
    //unsigned int ui_payload_len = 0;
    //unsigned int ui_begin_len = 0;
    //unsigned int ui_commit_len = 0;
    //unsigned int ui_rollback_len = 0;
    //char *p_req_payload = NULL;
    //char *p_begin_name = NULL;
    //char *p_commit_name = NULL;
    //char *p_rollback_name = NULL;
    //L7_req_sqlserver *p_st_req = NULL;

    /* 设置可能的TDS版本 */
    //i_cli_tds_min_ver = ((L7session_sqlserver_private *)p_st_session->p_session_private)->p_st_sess->i_cli_tds_min_ver;

    /* 跳过ALL_HEADERS */
    //__sqlserver_all_headers_skip(&p_inbuffer, &ui_buffer_len);

    /* RequestType是USHORT两个字节 */
    //if (ui_buffer_len < 2)
    //{
    //    return FR_FAIL;
    //}

    /* 取得RequestType */
    //ui_request_type = pletohl(p_inbuffer);
    //p_inbuffer += 2;
    //ui_buffer_len -= 2;

    /* 根据RequestType解析RequestPayload */
    //witch (ui_request_type)
    //
    //   case MSSQL_TM_GET_DTC_ADDRESS:
    //       i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_US_VARBYTE
    //                                     , FR_YES, &p_req_payload, &ui_payload_len);
    //       /* For RequestType TM_GET_DTC_ADDRESS: The RequestPayload SHOULD be a zero-length US_VARBYTE */
    //       if (i_ret != FR_SUCC || p_req_payload != NULL || ui_buffer_len != 0)
    //       {
    //           sqlserver_free((void **)p_req_payload);
    //           return FR_FAIL;
    //       }
    //       //todo 出力格式？
    //       break;

        /*
        * For RequestType TM_PROPAGATE_XACT: Data contains an opaque buffer used by
        * the server to enlist in a DTC transaction
        */
    //    case MSSQL_TM_PROPAGATE_XACT:
    //        i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_US_VARBYTE
    //                                      , FR_YES, &p_req_payload, &ui_payload_len);
    //        if (i_ret != FR_SUCC || ui_buffer_len != 0)
    //        {
    //            return FR_FAIL;
    //        }
    //        //todo 出力格式？
    //        break;

        /*
        * RequestPayload = ISOLATION_LEVEL
        *                    BEGIN_XACT_NAME
        */
    //   case MSSQL_TM_BEGIN_XACT:         /* introduced in TDS 7.2 */
    //       if (ui_buffer_len < 1)
    //       {
    //           return FR_FAIL;
    //       }
    //       uc_isolation_level = *p_inbuffer;
    //       p_inbuffer++;
    //       ui_buffer_len--;

    //       /* 取得transaction名 */
    //       i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_B_VARBYTE
    //                                     , FR_YES, &p_begin_name, &ui_begin_len);
    //       if (i_ret != FR_SUCC || ui_buffer_len != 0)
    //       {
    //           return FR_FAIL;
    //       }

    //       /* 设置TDS版本 */
    //       if (i_cli_tds_min_ver < MSSQL_TDS_VER_72)
    //       {
    //           i_cli_tds_min_ver = MSSQL_TDS_VER_72;
    //       }
    //       //todo 出力格式？
    //       break;

    //   case MSSQL_TM_PROMOTE_XACT:       /* introduced in TDS 7.2 */
    //       /* For RequestType TM_PROMOTE_XACT – No payload */
    //       if (ui_buffer_len != 0)
    //       {
    //           return FR_FAIL;
    //       }
    //       /* 设置TDS版本 */
    //       if (i_cli_tds_min_ver < MSSQL_TDS_VER_72)
    //       {
    //           i_cli_tds_min_ver = MSSQL_TDS_VER_72;
    //       }
    //       //todo 出力格式？
    //       break;

        /*
        * RequestPayload = XACT_NAME
        *                  XACT_FLAGS
        *                  [ISOLATION_LEVEL
        *                  BEGIN_XACT_NAME]
        */
    //   case MSSQL_TM_COMMIT_XACT:        /* introduced in TDS 7.2 */
    //       /* 取得transaction名 */
    //       i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_B_VARBYTE
    //                                     , FR_YES, &p_commit_name, &ui_commit_len);
    //       if (i_ret != FR_SUCC || ui_buffer_len < 1)
    //       {
    //           return FR_FAIL;
    //       }

    //       i_begin_xact_flag = 0x80 & (*p_inbuffer);
    //       p_inbuffer++;
    //       ui_buffer_len--;
    //       /* fBeginXact等于1时才有ISOLATION_LEVEL BEGIN_XACT_NAME */
    //       if (i_begin_xact_flag == 1)
    //       {
    //           /* 取得ISOLATION_LEVEL */
    //           if (ui_buffer_len < 1)
    //           {
    //               return FR_FAIL;
    //           }
    //           uc_isolation_level = *p_inbuffer;
    //           p_inbuffer++;
    //           ui_buffer_len--;
    //           /* 取得开始事务名 */
    //           i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_B_VARBYTE
    //                                         , FR_YES, &p_begin_name, &ui_begin_len);
    //           if (i_ret != FR_SUCC || ui_buffer_len != 0 || p_begin_name == NULL)
    //           {
    //               sqlserver_free((void **)&p_commit_name);
    //               return FR_FAIL;
    //           }
    //       }
    //       else if (ui_buffer_len != 0)
    //       {
    //           sqlserver_free((void **)&p_commit_name);
    //           return FR_FAIL;
    //       }

    //       /* 设置TDS版本 */
    //       if (i_cli_tds_min_ver < MSSQL_TDS_VER_72)
    //       {
    //           i_cli_tds_min_ver = MSSQL_TDS_VER_72;
    //       }
    //       //todo 出力格式？
    //       break;

        /*
        * RequestPayload = XACT_NAME
        *                  XACT_FLAGS
        *                  [ISOLATION_LEVEL
        *                  BEGIN_XACT_NAME]
        */
    //   case MSSQL_TM_ROLLBACK_XACT:      /* introduced in TDS 7.2 */
    //       /* 取得transaction名 */
    //       i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_B_VARBYTE
    //                                     , FR_YES, &p_rollback_name, &ui_rollback_len);
    //       if (i_ret != FR_SUCC || ui_buffer_len < 1)
    //       {
    //           return FR_FAIL;
    //       }

    //       i_begin_xact_flag = 0x80 & (*p_inbuffer);
    //       p_inbuffer++;
    //       ui_buffer_len--;
    //       /* fBeginXact等于1时才有ISOLATION_LEVEL BEGIN_XACT_NAME */
    //       if (i_begin_xact_flag == 1)
    //       {
    //           /* 取得ISOLATION_LEVEL */
    //           if (ui_buffer_len < 1)
    //           {
    //               return FR_FAIL;
    //           }
    //           uc_isolation_level = *p_inbuffer;
    //           p_inbuffer++;
    //           ui_buffer_len--;
    //           /* 取得开始事务名 */
    //           i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_B_VARBYTE
    //                                         , FR_YES, &p_begin_name, &ui_begin_len);
    //           if (i_ret != FR_SUCC || ui_buffer_len != 0)
    //           {
    //               sqlserver_free((void **)&p_rollback_name);
    //               return FR_FAIL;
    //           }
    //       }
    //       else if (ui_buffer_len != 0)
    //       {
    //           sqlserver_free((void **)&p_rollback_name);
    //           return FR_FAIL;
    //       }

    //       /* 设置TDS版本 */
    //       if (i_cli_tds_min_ver < MSSQL_TDS_VER_72)
    //       {
    //           i_cli_tds_min_ver = MSSQL_TDS_VER_72;
    //       }
    //       //todo 出力格式？
    //       break;

    //   case MSSQL_TM_SAVE_XACT:          /* introduced in TDS 7.2 */
    //       /* 取得transaction名 */
    //       i_ret = sqlserver_get_varbytes(&p_inbuffer, &ui_buffer_len, APM_TDS_B_VARBYTE
    //                                     , FR_YES, &p_req_payload, &ui_commit_len);
    //       /* A nonempty name MUST be specified as part of this request */
    //       if (i_ret != FR_SUCC || ui_buffer_len != 0 || p_req_payload == NULL)
    //       {
    //           return FR_FAIL;
    //       }

    //       /* 设置TDS版本 */
    //       if (i_cli_tds_min_ver < MSSQL_TDS_VER_72)
    //       {
    //           i_cli_tds_min_ver = MSSQL_TDS_VER_72;
    //       }
    //       //todo 出力格式？
    //       break;

    //   default:
    //       return FR_FAIL;
    //}

    /* 设置出力 todo */
    //((L7session_sqlserver_private *)p_st_session->p_session_private)->p_st_sess->i_cli_tds_min_ver = i_cli_tds_min_ver;
    //return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析ATTENTION
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (todo)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :  参照协议关于attention的描述
*******************************************************************************/
int sqlserver_parse_attention(Conntrack *p_st_conn
                             , L7session_sqlserver_private *p_st_private
                             , Frhash_header *p_st_hash_report
                             , int i_whole_flg)
{
    frdbg("Accept attention data!\n");
    /* 之前没有要被取消的request */
    if (p_st_private->p_st_req == NULL)
    {
        /* 做成request */
        p_st_private->p_st_req = slqserver_create_request(MSSQL_TDS_ATTENTION);
        if (p_st_private->p_st_req == NULL)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_private->p_st_req->i_cancel_flg = MSSQL_ATTENTION;
        p_st_private->p_st_req->i_need_req_resp = MSSQL_RESPONSE;
        return APM_L7_ANALYZE_SUCC;
    }

    /* 设置request */
    p_st_private->p_st_req->i_cancel_flg = MSSQL_ATTENTION;
    return APM_L7_ANALYZE_TODO;
}

/*******************************************************************************
*  FUNC     :  解析Bulk Load BCP
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_TODO  (todo)
*           :  APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     : 批量处理，现状是此处语句应该是在服务端本地组包执行，
*             packet数据在服务器本地通信，不经过网卡，故无法取得该packet数据，
*             因此在真实环境中应该是不会发生的
*             todo 若是能抓取到响应数据包时需要对应
*******************************************************************************/
int sqlserver_parse_bulk(Conntrack *p_st_conn
                        , L7session_sqlserver_private *p_st_private
                        , Frhash_header *p_st_hash_report
                        , int i_cancel_flg
                        , int i_whole_flg)
{
    /*
    * Bulk Load BCP定义如下：
        BulkLoadBCP =  BulkLoad_METADATA
                       *BulkLoad_ROW
                       BulkLoad_DONE
    * BulkLoad_METADATA = COLMETADATA_TOKEN
    * BulkLoad_ROW = ROW_TOKEN
    * BulkLoad_DONE = DONE_TOKEN
    */
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_BULKLOADBCP);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* Bulk Load BCP的没有大的数据,接收完了之后再解析 */
    if (i_whole_flg != FR_YES)
    {
        frdbg("Packet Bulk Load BCP: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    p_st_private->p_st_req->i_need_req_resp = MSSQL_RESPONSE;
    p_st_private->p_st_req->i_cancel_flg = i_cancel_flg;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析SSPI信息
*  ARGS     :  p_st_session(入力链接信息)
*           :  p_st_private(sqlserver私有信息)
*           :  p_st_hash_report(Frreport_data数据)
*           :  i_cancel_flg(packet的取消标识)
*           :  i_whole_flg(packet的完整性标识)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_TODO  (todo)
*           :  APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     : todo 未解析
*******************************************************************************/
int sqlserver_parse_sspi(Conntrack *p_st_conn
                        , L7session_sqlserver_private *p_st_private
                        , Frhash_header *p_st_hash_report
                        , int i_cancel_flg
                        , int i_whole_flg)
{
    /* 定义：
    * SSPI = SSPIData
    * SSPIData = BYTESTREAM
    */
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 判断创建request */
    i_ret = __sqlserver_chk_request(p_st_private, MSSQL_TDS_SSPIMESSAGE);
    if (i_ret != APM_L7_ANALYZE_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* SSPI的没有大的数据,接收完了之后再解析 */
    if (i_whole_flg != FR_YES)
    {
        frdbg("Packet SSPI: need more data!\n");
        return APM_L7_ANALYZE_TODO;
    }
    p_st_private->p_st_req->i_need_req_resp = MSSQL_RESPONSE;
    p_st_private->p_st_req->i_cancel_flg = i_cancel_flg;
    return APM_L7_ANALYZE_SUCC;
}
